home *** CD-ROM | disk | FTP | other *** search
- /* ReadDisk, 11 June 1999 *
- * Christophe GRENIER *
- * grenier@nef.esiea.fr *
- * http://www.esiea.fr/public_html/Christophe.GRENIER/ *
- * Based on readdisk.c from LRead by Werner Zimmermann */
- #include <stdio.h>
- #include <string.h>
- #define STDERR stdout /* Tell, where you'd like your error messages*/
- #include <stdlib.h>
- /*
- #include <bios.h>
- #include <dos.h>
- #include <conio.h>
- */
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include "types.h"
- #include "common.h"
- #include "hdaccess.h"
- #include "readdisk.h"
- #include "fnctdsk.h"
- //#include "km.h"
- enum {STATE_DIRTY, STATE_READ, STATE_WRITE};
- typedef struct {
- int C;
- int H;
- int S;
- int state;
- } t_cached;
- #define cache_size 500 // cache size in sectors => 256 Ko
- #define Nb_SuccSect 16 // 8 Ko per read
- #define DISK_BLOCK_SIZE 512
- unsigned char cache_buffer[cache_size][DISK_BLOCK_SIZE];
- t_cached cache_lst[cache_size];
-
- dword RS_offset;
-
- void *MALLOC(size_t size)
- { void *p=NULL;
- if (size)
- { p=malloc(size);
- }
- return(p);
- }
-
- void FREE(void *block)
- { if (block!=NULL)
- { free(block);
- }
- }
-
- /*Global Defines, but nothing to edit for users*/
- #define READ_CMD 2 /*Disk Read Command, do *NOT* change!!!*/
- #define WRITE_CMD 3 /*Disk Write Command, do *NOT* change!!!*/
- #define PARA_CMD 8 /*Disk Identify Command, do *NOT* change!!!*/
-
- #define NONE 0
- #define OK 1
- #define EXTENDED 2
- #define END_TABLE 3
-
- #define INIT 0
- #define KEEP_BUF 1 /*used to control free(buf) in read_inode()*/
- #define RELEASE_BUF 2
- #define KILL_BUF 3
-
- /* globals */
- t_param_disk disk_car;
- unsigned long start; /*logical block address(LBA) of your partition*/
- unsigned long num_sect; /*total # of sectors of your partition*/
- unsigned long pos_off;
- unsigned int disk_no; /*DOS' disk #, eg. 0x80=first harddisk*/
- unsigned int part_no; /*# of your partition*/
- int IN_DEV=0; /* holds the open input dev */
-
-
- int name2diskno(char *name)
- {
- if (strstr(name,"/dev/hda")) /* figure out disk number for DOS*/
- return 0x80;
- else if (strstr(name,"/dev/hdb"))
- return 0x81;
- else if (strstr(name,"/dev/hdc"))
- return 0x82;
- else if (strstr(name,"/dev/hdd"))
- return 0x83;
- else if (strstr(name,"/dev/sda"))
- return 0x80;
- else if (strstr(name,"/dev/sdb"))
- return 0x81;
- else if (strstr(name,"/dev/fd0"))
- return 0;
- else if (strstr(name,"/dev/fd1"))
- return 1;
- printf("Unknown Drive Specification: %s\n",name);
- return -1;
- }
-
- /*Convert Logical Block Number (LBA) adress to
- Cylinder-Head-Sector (CHS) address
- DOS and Linux software doesn't care about heads, sectors, cylinders, ie.
- your harddisk's hardware details and therefore works with LBA, but if you
- want to access your harddisk via the BIOS, you have to call the BIOS rou-
- tines with CHS addresses.
- */
-
- void convert(unsigned long x, unsigned int *head, unsigned int *track, \
- unsigned int *sector, unsigned int *offset)
- { unsigned long logicsect, absolsect;
-
- logicsect = x >> 9; /*divide by 512= harddisk sector size*/
- *offset = x & 0x1FF; /*modulo 512*/
- absolsect = logicsect+start;
-
- *track = absolsect / (disk_car->CHS.sector * (disk_car->CHS.head+1));
- *head = (absolsect / disk_car->CHS.sector) % (disk_car->CHS.head+1);
- *sector = (absolsect % disk_car->CHS.sector) + 1;
-
- if (absolsect > start+num_sect)
- { fprintf(STDERR,"You cannot access ABOVE the partition.\n");
- exit(-1);
- }
- }
-
- /* Christophe GRENIER 26/01/99 */
- int pos_read=0;
- unsigned long int sect_cached=0,sect_read=0;
-
- int do_read(int disk_no,int head,int cyl, int sect)
- {
- /*With floppys there are problems when trying to read beyond the last sector
- of a cylinder. So we try to deal with that. I never had this problem with
- harddisks, most likely, because my harddisks work in lba-mode, translating
- heads/sector/cylinder on their own. If we get read errors (rd!=0), the
- following piece of code needs to be improved
- */
- static int pos=-1;
- unsigned int rc=0, x,i,nb_sect;
- #ifdef DEBUG_READDISK
- fprintf(STDERR," do_read start - head:%u cyl:%u sect:%u no_sect:%lu\n",head,cyl,sect,num_sect);
- fflush(stderr);
- #endif
- sect_read++;
- if(pos==-1) /* Init cache */
- for(x=0;x<cache_size;x++) cache_lst[x].state=STATE_DIRTY;
- #ifndef NOCACHE
- for(x=0;x<cache_size;x++)
- {
- if( cache_lst[x].state==STATE_READ&& // Search in cache
- cache_lst[x].C==cyl&&
- cache_lst[x].H==head&&
- cache_lst[x].S==sect)
- {
- #ifdef DEBUG_READDISK
- printf("Cached\n");
- #endif
- sect_cached++;
- pos_read=x;
- return 0;
- }
- }
- #endif
- if(++pos>=cache_size) pos=0; /* circular method (simple but not the best) */
- nb_sect=cache_size-pos<Nb_SuccSect?cache_size-pos:Nb_SuccSect;
- if(nb_sect+sect>disk_car->CHS.sector) /* stay carrefully */
- nb_sect=disk_car->CHS.sector-sect+1; /* on the same cylinder and head */
- // nb_sect=1;
- {
- t_diskext partition=MALLOC(sizeof(*partition));
- partition->disk=disk_no;
- partition->start.cylinder=cyl;
- partition->start.head=head;
- partition->start.sector=sect;
- if(hd_read2(disk_car,nb_sect,&cache_buffer[pos],partition))
- {
- printf("\nErreur de lecture");
- }
- FREE(partition);
- }
- pos_read=pos;
- for(i=0;i<nb_sect;i++)
- {
- cache_lst[pos].state=STATE_READ;
- cache_lst[pos].C=cyl;
- cache_lst[pos].H=head;
- cache_lst[pos].S=sect;
- sect++;
- /* Not necessairy
- if(++sect>disk_car->CHS.sector)
- { sect=1;
- if(++head>=HEADS)
- { head=0;cyl++; }
- }
- */
- pos++;
- }
- #ifdef DEBUG_READDISK
- fflush(stdout);
- fflush(stderr);
- printf("\ndo_read end");
- fflush(stdout);
- #endif
- return rc;
- }
-
- int readdisk( unsigned char *buf, unsigned long loc, unsigned long size )
- {
- unsigned int head,cyl,sect,offset;
- unsigned int no_sect;
- unsigned int i; //,rc;
- unsigned char *temp;
- #ifdef DEBUG_READDISK
- printf("--------Executing 'readdisk'--*buf:%u--size:%lu--loc:%lu\n",*buf,size,loc);
- fflush(stdout);
- #endif
-
- convert (loc,&head,&cyl,§,&offset);
-
- no_sect= (offset+size)>>9;
- if ((offset+size)&0x1FF) no_sect++;
- if (no_sect<2)
- {
- if (disk_no<128) no_sect=1; /*with floppys: minimum read is 1 sector*/
- else no_sect=2; /*with harddisks: 2 sectors*/
- }
- temp=(unsigned char *) MALLOC(no_sect*512);
- for(i=0;i<no_sect;i++)
- {
- #ifdef DEBUG_READDISK
- printf("%d/%d->",i+1,no_sect);
- fflush(stdout);
- #endif
- if(do_read(disk_no,head,cyl,sect)) return 0;
- memcpy(&temp[i*DISK_BLOCK_SIZE],&cache_buffer[pos_read],DISK_BLOCK_SIZE);
- if(++sect>disk_car->CHS.sector)
- { sect=1;
- if(++head>disk_car->CHS.head)
- { head=0;cyl++; }
- }
- }
- memcpy(buf,&temp[offset],size);
- FREE(temp);
- #ifdef DEBUG_READDISK
- printf("--------readdisk end\n");
- fflush(stdout);
- printf("readdisk ");
- for(i=0;i<0x10;i++)
- printf("%02X ",*(char*)(buf+i));
- printf("\n");
- fflush(stdout);
- #endif
- return size;
- }
-
- int writedisk( unsigned char *buf, unsigned long loc, size_t size )
- {
- unsigned int head,cyl,sect,offset;
- unsigned int rc=0, x;
- unsigned long no_sect;
- for(x=0;x<cache_size;x++) cache_lst[x].state=STATE_DIRTY;
- convert (loc,&head,&cyl,§,&offset);
- if((offset==0)&&(size%512==0))
- {
- t_diskext partition=MALLOC(sizeof(*partition));
- no_sect=size>>9;
- partition->disk=disk_no;
- partition->start.cylinder=cyl;
- partition->start.head=head;
- partition->start.sector=sect;
-
- if(hd_write2(disk_car,no_sect,buf,partition))
- {
- printf("\nErreur de lecture");
- }
- FREE(partition);
- }
- else
- {
- static unsigned char *temp;
- t_diskext partition=MALLOC(sizeof(*partition));
- #ifdef DEBUG_READDISK
- printf("\nExperimental Write");
- fflush(stdout);
- #endif
- no_sect= (size+loc%512) >> 9;
- if(size+loc%512!=0)
- no_sect++;
- temp=(unsigned char *) MALLOC(no_sect*512);
- readdisk(temp, (loc>>9)*512,no_sect*512); /* in fact, only need beginning and ending*/
- memcpy(&temp[offset],buf,size); /* no ending NULL */
- partition->disk=disk_no;
- partition->start.cylinder=cyl;
- partition->start.head=head;
- partition->start.sector=sect;
- if(hd_write2(disk_car,no_sect,temp,partition))
- {
- printf("\nErreur de lecture");
- }
- FREE(partition);
- FREE(temp);
- }
- if (rc==0)
- return size;
- else
- {
- fprintf(STDERR,"Error %x in Write Disk - loc:%lu head:%u cyl:%u sect:%u no_sect:%lu\n",rc,loc,head,cyl,sect,num_sect);
- return 0;
- }
- }
-
- off_t lseek_dev(int fd, off_t offset, int whence)
- {
- switch(whence)
- {
- case(SEEK_SET):
- pos_off=offset;
- break;
- case(SEEK_CUR):
- pos_off+=offset;
- break;
- case(SEEK_END):
- pos_off=num_sect+offset;
- break;
- }
- return pos_off;
- }
-
- ssize_t read_dev(int fd, void *buffer, size_t length)
- {
- ssize_t tmp;
- #ifdef DEBUG_READDISK
- printf("Read dev - length %ld\n",length);
- #endif
- tmp=readdisk(buffer,pos_off,length);
- pos_off+=length;
- return tmp;
- }
-
- ssize_t write_dev(int fd, void *buffer, size_t length)
- {
- ssize_t tmp=writedisk(buffer,pos_off,length);
- pos_off+=length;
- return tmp;
- }
-
- /*This procedure looks for your partition.
- You have to specify the disk to search via the -s or -f command
- line switch, specification is done in Linux 'style', your specification is
- converted into a DOS 'style' specification in global variables disk_no and
- part_no, eg.:
-
- /dev/hdaX first harddisk disk_no=0x80
- /dev/hdbX second harddisk 0x81
- /dev/fd0 first floppy disk 0x00
- /dev/fd1 second floppy disk 0x01
-
- If you do not specify a partition number, i.e. if X is a space, the procedure
- will search the four entrys of the partition table for a primary
- partition, if it finds one, it will use it. If it does not find a primary
- partition, it searches for an DOS extended partition, read's the
- DOS extended partition's table and searches it for a partition.
- As DOS extended partitions may contain an unlimited number of 'logical drives',
- this search is recursively until we find a "good type" partition or until we
- reach the end of the tables.
-
- If you additionally specify a partition number, i.e. set X to 5, for each
- NTFS partition we find we also check, if its the specified partition num-
- ber. If not, we continue the search of the partition table. The partition
- number is transfered to the procedure via global variable part_no.
- */
-
- int examine_drive(uint disk_num, uint part_num,int open_mode,int debug)
- { int i,k,kfound=0,p=0,ptemp=0;
- static unsigned char *buf;
- char found=NONE;
- unsigned char run[4][16];
- t_diskext partition=MALLOC(sizeof(*partition));
- if(disk_car==NULL)
- disk_car=MALLOC(sizeof(*disk_car));
-
- RS_offset=1;
- partition->disk=disk_num;
- partition->start.cylinder=0;
- partition->start.head=0;
- partition->start.sector=1;
- part_no=part_num;
- buf=(unsigned char *) MALLOC(512);
- start=0;
- disk_car->disk=disk_num;
- if(hd_identify(disk_car,debug))
- return 1;
- if ((partition->disk==0)||(partition->disk==1)) /*Is it a floppy drive? 0=A: 1=B:*/
- { start = (long) 0; /*floppy's do not have partitions*/
- num_sect = (disk_car->CHS.head+1)*disk_car->CHS.sector*(disk_car->CHS.cylinder+1);
- FREE(partition);
- FREE(buf);
- return 0;
- }
-
- /* read the partition table from the first hard drive, partition table starts at CHS=0 0 1*/
- if(hd_read2(disk_car,1,buf,partition))
- return 1; /*if the BIOS can't read the partition table*/
- for (k=0;k<4;k++) /*Search the Primary Partition Table for a Linux partition*/
- {
- for (i=0;i<16;i++) /*The partition table has 4 entrys with 16 bytes per entry*/
- run[k][i] = buf[446+(k*16)+i]; /*it starts at byte 446 in the harddisk's first sector*/
- if ((run[k][4]==0x7)||(run[k][4]==0x17))
- { if ((part_no==0)||(k==part_no-1)) /*we found a good partition, but does it have the correct partition number?*/
- { found=OK;
- kfound=k; /*yes*/
- }
- else
- ptemp=k+1; /*no*/
- }
- #ifdef DEBUG
- printf("found %d, kfound %d\n",found,kfound);
- #endif
- }
- if (found!=OK) /*We haven't found a "good type" primary partition, so we search for an extended partition*/
- { for (k=0;k<4;k++)
- {
- if ((run[k][4]==0x05)||(run[k][4]==0x0F)) /*0x05 is the signature for extended partitions*/
- { found=EXTENDED;
- p=5; /*Extended partitions start at /dev/hd?5*/
- kfound=k;
- }
- #ifdef DEBUG
- printf("found ext %d, kfound %d\n",found,kfound);
- #endif
- }
- }
- if(found!=NONE)
- entree2partition(disk_car,1,partition,run[kfound],STATUS_PRIM);
- if (found==EXTENDED) /*Searching extended partition table*/
- {
- dword pos=get_SR_part(disk_car,partition);
- do
- {
- printf("p=%d\n",p);
- found=NONE;
- entree2partition(disk_car,pos,partition,run[kfound],STATUS_EXT_IN_EXT);
- if(hd_read2(disk_car,1,buf,partition))
- return 1;
- if((buf[0x1FE]!=0x55)||(buf[0x1FF]!=0xAA))
- return 1;
- /*get the partitions CHS address from the partition table*/
- /*Check extended Partition Table, same game as with the primary table*/
- /*The extended partition table has 2 entrys with 16 bytes per entry*/
- /*where one entry can be another extended partition*/
- for (k=0;k<2;k++)
- { for (i=0;i<16;i++)
- run[k][i] = buf[446+(k*16)+i];
- if ((run[k][4]==0x05)||(run[k][4]==0x0F))
- { found=EXTENDED; /*hurrah, another extended partion*/
- kfound=k;
- p++;
- }
- if ((run[k][4]==0x7)||(run[k][4]==0x17)) /*hurrah */
- { if ((part_no==0)||(p==part_no)) /*does it have the correct partition number?*/
- { found=OK;
- kfound=k; /*yes*/
- }
- else
- ptemp=p; /*no*/
- }
- if(RS_offset==1)
- RS_offset=pos;
- }
- // } while ((run[1][4]!=0) && (found!=OK) && (buf[510]==0x55) && (buf[511]==0xAA));
- } while ((run[1][4]!=0) && (found==EXTENDED) && (buf[510]==0x55) && (buf[511]==0xAA));
- if(found!=NONE)
- entree2partition(disk_car,pos,partition,run[kfound],STATUS_LOG);
- }
- /*our search continues until either -we found the last entry which's signature is 0
- or -we found the right good partition
- or -the sector is not a partition table (signature 0xAA55*/
-
- if (found!=OK) /*if we finally did not find the partition*/
- {
- if (ptemp>0)
- fprintf(STDERR,"Found at partition number %i\n",ptemp);
- return 2;
- }
-
- /*if we reach this point, we've found the right partition*/
- /*get the partitions CHS address from the partition table*/
- start=get_LBA_part(disk_car,partition);
- num_sect=partition->part_size;
- #ifdef DEBUG
- printf("start %ld num_sect %ld\n",start,num_sect);
- #endif
- FREE(partition);
- FREE(buf);
- return 0;
- }
-
- int open_dev(char *name , int open_mode)
- {
- int tmp;
- char *temp;
- unsigned int disk_no;
- unsigned int part_no;
- int debug=0;
- if (strlen(name)==0)
- {
- for(disk_no=0x80;disk_no<0x84;disk_no++)
- if((tmp=examine_drive(disk_no,0, open_mode,debug))!=2)
- break;
- if(tmp!=0)
- {
- fprintf(STDERR,"\nNo partition found");
- return -1;
- }
- }
- else
- {
- if((disk_no=name2diskno(name))==-1)
- return -1;
- if (disk_no>=0x80) /*do it only for harddisks ???*/
- {
- if (strstr(name,"dev/hd"))
- temp=strtok(name,"/dev/hd");
- else
- { temp=strtok(name,"dev/sd");
- fprintf(STDERR,"SCSI drive support is experimental\n");
- }
- part_no=temp[1]-0x30; /*convert char to int*/
- if ((part_no<1)||(part_no>9))
- part_no=0;
- }
- else
- part_no=1; /*on floppy disks we only have one partition*/
- tmp=examine_drive(disk_no,part_no,open_mode,debug);
- switch(tmp)
- {
- case 1:
- fprintf(STDERR,"Error Reading Partition Table on %s\n",name);
- break;
- case 2:
- fprintf(STDERR,"Could not find partition on %s\n",name);
- break;
- }
- if(tmp!=0)
- {
- fprintf(STDERR,"//hdx[y]/path ,\n"
- "where x=a,b,... is the harddisk and\n"
- "y=1,2,... (may be omitted) is your partition number\n");
- return -1;
- }
- }
- return 10;
- }
-